<?php

/**
 * JPGraph v4.0.3
 */

namespace lemon\JpGraph\Plot;

use lemon\JpGraph\Util;

/**
 * @class AccLinePlot
 * // Description:
 */
class AccLinePlot extends Plot
{
	protected $plots;
	protected $nbrplots	= 0;
	private $iStartEndZero = true;

	/**
	 * CONSTRUCTOR.
	 *
	 * @param mixed $plots
	 */
	public function __construct($plots)
	{
		$this->plots	 = $plots;
		$this->nbrplots  = safe_count($plots);
		$this->numpoints = $plots[0]->numpoints;

		// Verify that all plots have the same number of data points
		for ($i = 1; $i < $this->nbrplots; ++$i) {
			if ($plots[$i]->numpoints != $this->numpoints) {
				Util\JpGraphError::RaiseL(10003); //('Each plot in an accumulated lineplot must have the same number of data points',0)
			}
		}

		for ($i = 0; $i < $this->nbrplots; ++$i) {
			$this->LineInterpolate($this->plots[$i]->coords[0]);
		}
	}

	/**
	 * PUBLIC METHODS.
	 *
	 * @param mixed $graph
	 */
	public function Legend($graph)
	{
		foreach ($this->plots as $p) {
			$p->DoLegend($graph);
		}
	}

	public function Max()
	{
		list($xmax) = $this->plots[0]->Max();
		$nmax	   = 0;
		$n		  = safe_count($this->plots);
		for ($i = 0; $i < $n; ++$i) {
			$nc	  = safe_count($this->plots[$i]->coords[0]);
			$nmax	= max($nmax, $nc);
			list($x) = $this->plots[$i]->Max();
			$xmax	= max($xmax, $x);
		}
		for ($i = 0; $i < $nmax; ++$i) {
			// Get y-value for line $i by adding the
			// individual bars from all the plots added.
			// It would be wrong to just add the
			// individual plots max y-value since that
			// would in most cases give to large y-value.
			$y = $this->plots[0]->coords[0][$i];
			for ($j = 1; $j < $this->nbrplots; ++$j) {
				$y += $this->plots[$j]->coords[0][$i];
			}
			$ymax[$i] = $y;
		}
		$ymax = max($ymax);

		return [$xmax, $ymax];
	}

	public function Min()
	{
		$nmax				 = 0;
		list($xmin, $ysetmin) = $this->plots[0]->Min();
		$n					= safe_count($this->plots);
		for ($i = 0; $i < $n; ++$i) {
			$nc		  = safe_count($this->plots[$i]->coords[0]);
			$nmax		= max($nmax, $nc);
			list($x, $y) = $this->plots[$i]->Min();
			$xmin		= min($xmin, $x);
			$ysetmin	 = min($y, $ysetmin);
		}
		for ($i = 0; $i < $nmax; ++$i) {
			// Get y-value for line $i by adding the
			// individual bars from all the plots added.
			// It would be wrong to just add the
			// individual plots min y-value since that
			// would in most cases give to small y-value.
			$y = $this->plots[0]->coords[0][$i];
			for ($j = 1; $j < $this->nbrplots; ++$j) {
				$y += $this->plots[$j]->coords[0][$i];
			}
			$ymin[$i] = $y;
		}
		$ymin = min($ysetmin, min($ymin));

		return [$xmin, $ymin];
	}

	// Gets called before any axis are stroked
	public function PreStrokeAdjust($graph)
	{
		// If another plot type have already adjusted the
		// offset we don't touch it.
		// (We check for empty in case the scale is  a log scale
		// and hence doesn't contain any xlabel_offset)

		if (empty($graph->xaxis->scale->ticks->xlabel_offset) ||
			$graph->xaxis->scale->ticks->xlabel_offset == 0) {
			if ($this->center) {
				++$this->numpoints;
				$a = 0.5;
				$b = 0.5;
			} else {
				$a = 0;
				$b = 0;
			}
			$graph->xaxis->scale->ticks->SetXLabelOffset($a);
			$graph->SetTextScaleOff($b);
			$graph->xaxis->scale->ticks->SupressMinorTickMarks();
		}
	}

	public function SetInterpolateMode($aIntMode)
	{
		$this->iStartEndZero = $aIntMode;
	}

	// Replace all '-' with an interpolated value. We use straightforward
	// linear interpolation. If the data starts with one or several '-' they
	// will be replaced by the the first valid data point
	public function LineInterpolate(&$aData)
	{
		$n = safe_count($aData);
		$i = 0;

		// If first point is undefined we will set it to the same as the first
		// valid data
		if ($aData[$i] === '-') {
			// Find the first valid data
			while ($i < $n && $aData[$i] === '-') {
				++$i;
			}
			if ($i < $n) {
				for ($j = 0; $j < $i; ++$j) {
					if ($this->iStartEndZero) {
						$aData[$i] = 0;
					} else {
						$aData[$j] = $aData[$i];
					}
				}
			} else {
				// All '-' => Error
				return false;
			}
		}

		while ($i < $n) {
			while ($i < $n && $aData[$i] !== '-') {
				++$i;
			}
			if ($i < $n) {
				$pstart = $i - 1;

				// Now see how long this segment of '-' are
				while ($i < $n && $aData[$i] === '-') {
					++$i;
				}
				if ($i < $n) {
					$pend = $i;
					$size = $pend - $pstart;
					$k	= ($aData[$pend] - $aData[$pstart]) / $size;
					// Replace the segment of '-' with a linear interpolated value.
					for ($j = 1; $j < $size; ++$j) {
						$aData[$pstart + $j] = $aData[$pstart] + $j * $k;
					}
				} else {
					// There are no valid end point. The '-' goes all the way to the end
					// In that case we just set all the remaining values the the same as the
					// last valid data point.
					for ($j = $pstart + 1; $j < $n; ++$j) {
						if ($this->iStartEndZero) {
							$aData[$j] = 0;
						} else {
							$aData[$j] = $aData[$pstart];
						}
					}
				}
			}
		}

		return true;
	}

	// To avoid duplicate of line drawing code here we just
	// change the y-values for each plot and then restore it
	// after we have made the stroke. We must do this copy since
	// it wouldn't be possible to create an acc line plot
	// with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl));
	// since this method would have a side effect.
	public function Stroke($img, $xscale, $yscale)
	{
		$img->SetLineWeight($this->weight);
		$this->numpoints = safe_count($this->plots[0]->coords[0]);
		// Allocate array
		$coords[$this->nbrplots][$this->numpoints] = 0;
		for ($i = 0; $i < $this->numpoints; ++$i) {
			$coords[0][$i] = $this->plots[0]->coords[0][$i];
			$accy		  = $coords[0][$i];
			for ($j = 1; $j < $this->nbrplots; ++$j) {
				$coords[$j][$i] = $this->plots[$j]->coords[0][$i] + $accy;
				$accy		   = $coords[$j][$i];
			}
		}
		for ($j = $this->nbrplots - 1; $j >= 0; --$j) {
			$p = $this->plots[$j];
			for ($i = 0; $i < $this->numpoints; ++$i) {
				$tmp[$i]		  = $p->coords[0][$i];
				$p->coords[0][$i] = $coords[$j][$i];
			}
			$p->Stroke($img, $xscale, $yscale);
			for ($i = 0; $i < $this->numpoints; ++$i) {
				$p->coords[0][$i] = $tmp[$i];
			}
			$p->coords[0][] = $tmp;
		}
	}
} // @class
